home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 2007 December
/
PCWKCD1207B.iso
/
Blogowanie poza sfera
/
Flock 1.0 beta
/
flock-1.0RC3.en-US.win32.exe
/
flock
/
modules
/
FlockXPCOMUtils.jsm
< prev
next >
Wrap
Text File
|
2007-10-18
|
16KB
|
381 lines
//
// BEGIN FLOCK GPL
//
// Copyright Flock Inc. 2005-2007
// http://flock.com
//
// This file may be used under the terms of of the
// GNU General Public License Version 2 or later (the "GPL"),
// http://www.gnu.org/licenses/gpl.html
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
// for the specific language governing rights and limitations under the
// License.
//
// END FLOCK GPL
//
// This code is based on the Javascript part of the proposed patch
// to Mozilla found here:
//
// https://bugzilla.mozilla.org/show_bug.cgi?id=71689
//
// Bugzilla Bug 71689 - Need helper utilities for JS component authors
// "They suffer without a generic module implementation, and the
// cutting-and-pasting breaks my little heart." (a-yup)
//
// All objects in here become properties on the 'FlockXPCOMUtils' object.
const CC = Components.classes;
const CI = Components.interfaces;
const CR = Components.results;
var EXPORTED_SYMBOLS = [ "FlockXPCOMUtils" ];
debug("*** loading FlockXPCOMUtils\n");
var FlockXPCOMUtils = {
debug: false,
/**
* Creates an NSGetModule function that returns the result of calling
* genericModule with the same parameters.
*/
generateNSGetModule: function FlockXPCOMUtils_generateNSGetModule(aName, aComponentsArray) {
return function FlockXPCOMUtils_NSGetModule(aCompMgr, aFileSpec) {
return new FlockXPCOMUtils.genericModule(aName, aComponentsArray);
};
},
/**
* Creates a generic Javascript XPCOM module to contain one or more XPCOM
* components also written in Javascript.
*
* @param aName (in) A descriptive name for the module. Only used for
* identifying purposes in debug messages.
* @param aComponentsArray (in)
*
* @return An object that implements the methods required to participate in
* XPCOM: registerSelf, unregisterSelf, getClassObject, canUnload.
*/
genericModule: function FlockXPCOMUtils_genericModule(aName, aComponentsArray) {
// the first argument is the module name (used for debugging only)
this.moduleName = aName;
// and the second is an array of components
this.classes = [];
for each (let component in aComponentsArray) {
this.classes.push(FlockXPCOMUtils.classDescForComponent(component));
}
// use FlockXPCOMUtils as the default for printing debugging statements
this.debug = FlockXPCOMUtils.debug;
// override printDebug() to make messages slightly more informative
this.printDebug = function genericModule_printDebug(message) {
if (this.debug) {
FlockXPCOMUtils.printDebug("FlockXPCOMUtils Mod: " + this.moduleName + ": " + message);
}
};
if (this.classes.length === 0) {
this.printDebug("(WARNING) no components given to genericModule");
}
this.registerSelf = function genericModule_registerSelf(aCompMgr, aFileSpec, aLocation, aType) {
this.printDebug("entering registerSelf...");
var registrar = aCompMgr.QueryInterface(CI.nsIComponentRegistrar);
for each (let classDesc in this.classes) {
this.printDebug(" registering component '" + classDesc.className + "'");
registrar.registerFactoryLocation(classDesc.classID,
classDesc.className,
classDesc.contractID,
aFileSpec,
aLocation,
aType);
FlockXPCOMUtils.addCategories(classDesc);
// callback to allow component specific registration
classDesc.register(aCompMgr, aFileSpec, aLocation, aType);
}
this.printDebug("leaving registerSelf");
};
this.unregisterSelf = function genericModule_unregisterSelf(aCompMgr, aFileSpec, aLocation) {
this.printDebug("entering unregisterSelf...");
var registrar = aCompMgr.QueryInterface(CI.nsIComponentRegistrar);
for each (let classDesc in this.classes) {
this.printDebug(" unregistering component '" + classDesc.className + "'");
// callback to allow classDesc specific unregistration
classDesc.unregister(aCompMgr, aFileSpec, aLocation, aType);
FlockXPCOMUtils.deleteCategories(classDesc);
registrar.unregisterFactoryLocation(classDesc.classID, aFileSpec);
}
this.printDebug("leaving unregisterSelf");
};
this.getClassObject = function genericModule_getClassObject(aCompMgr, aCID, iid) {
this.printDebug("getClassObject() called");
// XXX: Right now, we only support nsIFactory queries, not nsIClassInfo
// However, we do provide an nsIClassInfo for components that use us
// so perhaps we *could*. But I'm unsure about the semantics, and
// there appears to be no users of that feature in the tree. -Manish
if (!iid.equals(CI.nsIFactory)) {
this.printDebug("(error) iid was '" + iid + "'");
throw CR.NS_ERROR_NOT_IMPLEMENTED;
}
for each (let classDesc in this.classes) {
if (aCID.equals(classDesc.classID)) {
this.printDebug(" ClassID MATCHES component '" + classDesc.className + "'");
return classDesc.factory;
}
this.printDebug(" ClassID does not match component '" + classDesc.className + "'");
}
// no component had a matching contract id
this.printDebug("(ERROR) unable to match cid='" + aCID + "'");
throw CR.NS_ERROR_FACTORY_NOT_REGISTERED;
};
this.QueryInterface = function genericModule_QueryInterface(iid) {
if (iid.equals(CI.nsIModule) ||
iid.equals(CI.nsISupports))
{
return this;
}
throw CR.NS_ERROR_NO_INTERFACE;
};
this.canUnload = function genericModule_canUnload(aCompMgr) {
this.printDebug("canUnload called");
return true; // return value is ignored for javascript components
};
},
/**
* Creates a generic Javascript XPCOM component with a set of predefined
* interfaces: nsISupports, nsISupportsPrimitive, nsISupportsCString, nsIClassInfo.
*
* @param aName (in) A descriptive name for the component. Becomes the
* nsIClassInfo property "classDescription"
* @param aCID (in) The ClassID for this component.
* @param aContractID (in) The ContractID for this component.
* @param aCtor (in) The constuctor for the object. Usage: return new aCtor();
* @param aClassFlags (in) Class from nsIClassInfo flags ORed together. To make
* your component a singleton,
* use Components.interfaces.nsIClassInfo.SINGLETON.
* @param aInterfaceArray (in) The list of interfaces the component supports.
* Do not list any of the predefined interfaces here.
* Example:
* [Components.interfaces.flockILoggingService, Components.interfaces.nsIObserver]
* @return An object that implements a class factory for the listed interfaces, and
* can be QueryInterfaced()'ed for any of the supported interfaces.
*
* @see nsIClassInfo
*/
genericComponent: function FlockXPCOMUtils_genericComponent(aName, aCID, aContractID, aCtor, aClassFlags, aInterfaceArray) {
// We need to use "this" as it was during component creation, so we
// take a copy now. Within genericComponent(), references to "this"
// are from the context of the caller of the defined function.
var inst = this;
inst.ctor = aCtor; // For creating new instances
inst.classDescription = aName; // Property of nsIClassInfo interface
// use FlockXPCOMUtils as the default for printing debugging statements
inst.showdebug = FlockXPCOMUtils.debug;
// override printDebug() to make messages slightly more informative
inst.printDebug = function genericComponent_printDebug(message) {
if (inst.showdebug) {
FlockXPCOMUtils.printDebug("FlockXPCOMUtils Cmp: " +inst.classDescription+ ": " + message);
}
};
// Build the list of interfaces supported by the component.
inst.interfaceArray = [];
// All components have nsISupports, so add it automatically.
inst.interfaceArray.push(Components.interfaces.nsISupports);
// We provide nsIClassInfo for components using this module.
inst.interfaceArray.push(Components.interfaces.nsIClassInfo);
inst.predefinedInterfaceCount = inst.interfaceArray.length;
// Record the interfaces supported by the component.
for (var i = 0; i < aInterfaceArray.length; i++) {
inst.interfaceArray.push(aInterfaceArray[i]);
}
// Check that the caller actually gave an interface to use
if (inst.interfaceArray.length === inst.predefinedInterfaceCount) {
inst.printDebug("(WARNING) no user specified interfaces");
}
// warn if it is obvious something else has been passed instead of a CID
// (the raw xpconnect error is obscure enough to warrant a warning)
if (typeof(aCID) !== "object") {
inst.printDebug("(WARNING) cid '" + aCID + "' is not an object!");
}
// register() is a callback from genericModule.registerSelf()
inst.register = function genericComponent_register(aCompMgr, aFileSpec, aLocation, aType) {
inst.printDebug("register called on component '" + this.classDescription + "'");
return; // user overrides 'register()' for component specific registration
};
// unregister() is a callback from genericModule.unregisterSelf()
inst.unregister = function genericComponent_unregister(aCompMgr, aFileSpec, aLocation, aType) {
inst.printDebug("unregister called on component '" + this.classDescription + "'");
return; // user can override for component specific unregistration
};
// Convenience wrapper around FlockXPCOMUtils.addCategories
inst.addCategories = function genericComponent_addCategories() {
inst.printDebug("instance manually adding categories");
var classDesc = FlockXPCOMUtils.classDescForComponent(inst.ctor);
FlockXPCOMUtils.addCategories(classDesc);
};
// Convenience wrapper around FlockXPCOMUtils.deleteCategories
inst.deleteCategories = function genericComponent_deleteCategories() {
inst.printDebug("instance manually deleting categories");
var classDesc = FlockXPCOMUtils.classDescForComponent(inst.ctor);
FlockXPCOMUtils.deleteCategories(classDesc);
};
// nsISupports interface
inst.QueryInterface = function genericComponent_QueryInterface(iid) {
inst.printDebug("QueryInterface called");
// see if component object supports the requested interface
for (i = 0; i < inst.interfaceArray.length; i++) {
if (iid.equals(inst.interfaceArray[i])) {
inst.printDebug(" MATCHED interface '" + inst.interfaceArray[i] + "'");
return this;
}
}
if (inst.showdebug) { // expensive but rare check to get better debug message
for (var name in Components.interfaces) {
if (iid.equals(Components.interfaces[name])) {
inst.printDebug(" NS_ERROR_NO_INTERFACE on QI for '" + name + "'");
throw Components.results.NS_ERROR_NO_INTERFACE;
}
}
inst.printDebug(" NS_ERROR_NO_INTERFACE on QI for '" + iid + "'");
}
throw Components.results.NS_ERROR_NO_INTERFACE;
};
// nsIClassInfo interface
inst.getInterfaces = function genericComponent_getInterfaces(aCount) {
var iids = [];
for (i = 0; i < inst.interfaceArray.length; i++) {
iids.push(inst.interfaceArray[i]);
}
aCount.value = iids.length;
return iids;
};
inst.getHelperForLanguage = function genericComponent_getHelperForLanguage(aLanguage) { return null; };
inst.contractID = aContractID;
inst.classID = aCID;
inst.implementationLanguage = Components.interfaces.nsIProgrammingLanguage.JAVASCRIPT;
// See xpcom/components/nsIClassInfo.idl for more flags.
inst.flags = aClassFlags;
// required by nsIFactory so define to prevent warnings
inst.lockFactory = function genericComponent_lockFactory(lock) {
inst.printDebug("lockFactory() called");
return true;
};
// nsIFactory function pointed to by module.getClassObject()
inst.createInstance = function genericComponent_createInstance(outer, iid) {
inst.printDebug("createInstance called for " + inst.classDescription);
if (outer) {
/* FIXME: tell me again why don't we handle aggregation? */
inst.printDebug("(ERROR) interface does not allow aggregation");
throw Components.results.NS_ERROR_NO_AGGREGATION;
}
inst.printDebug(" creating new instance and querying for interface");
return (new inst.ctor()).QueryInterface(iid);
};
},
// helper function to add an entry to the category manager
addCategoryEntry: function FlockXPCOMUtils_addCategoryEntry(category, name, value) {
this.printDebug("FlockXPCOMUtils addCategory: adding '"
+ name
+ "' to category '"
+ category
+ "'");
/* NOTE: different categories use different entries for name and value */
this.categoryManager.addCategoryEntry(category, name, value, true, true);
},
// helper function to remove an entry from the category manager
deleteCategoryEntry: function FlockXPCOMUtils_deleteCategoryEntry(category, name) {
this.printDebug("FlockXPCOMUtils deleteCategory: deleting '"
+ name
+ "' from category '"
+ category
+ "'");
this.categoryManager.deleteCategoryEntry(category, name, true);
},
// helper function add categories to the category manager out of
// component.prototype._xpcom_categories
addCategories: function FlockXPCOMUtils_addCategories(classDesc) {
if (classDesc.categories) {
for each (let cat in classDesc.categories) {
let defaultValue = (cat.service ? "service," : "") +
classDesc.contractID;
this.addCategoryEntry(cat.category,
cat.entry || classDesc.className,
cat.value || defaultValue);
}
}
},
// helper function delete categories to the category manager out of
// component.prototype._xpcom_categories
deleteCategories: function FlockXPCOMUtils_deleteCategories(classDesc) {
if (classDesc.categories) {
for each (let cat in classDesc.categories) {
this.deleteCategoryEntry(cat.category,
cat.entry || classDesc.className);
}
}
},
classDescForComponent: function FlockXPCOMUtils_classDescForComponent(aComponent) {
return {
classID: aComponent.prototype.classID,
className: aComponent.prototype.classDescription,
contractID: aComponent.prototype.contractID,
factory: aComponent.prototype, // component acts as its own nsIFactory
categories: aComponent.prototype._xpcom_categories,
register: aComponent.prototype.register,
unregister: aComponent.prototype.unregister
};
},
get categoryManager() {
return CC["@mozilla.org/categorymanager;1"]
.getService(CI.nsICategoryManager);
},
// print a debug message (turn on and off via FlockXPCOMUtils.debug)
printDebug: function FlockXPCOMUtils_printDebug(message) {
if (this.debug) dump(message + "\n");
}
}; // var FlockXPCOMUtils